import datetime
import logging
import time

import pandas as pd
import talib as ta
from binance.um_futures import UMFutures
from . import BinanceKlinesTool


def get_oder_data(klines, symbol: str, interval: str):
    data = UMFutures().klines(symbol, interval, **{"limit": 1500})
    for i in range(0, len(data) - 1):
        klines = oder_klines_concat(klines, date=data[i][0], open=data[i][1], close=data[i][4], high=data[i][2],
                                    low=data[i][3], volume=data[i][5], value=data[i][7])

    date = time.time()
    date = int(round(date * 1000))
    klines = now_klines_concat(klines, date=date, open=data[-1][1], close=data[-1][4], high=data[-1][2],
                               low=data[-1][3], volume=data[-1][5], value=data[-1][7], interval=interval)
    return klines


def get_last_kline(symbol: str, interval: str):
    kline = pd.DataFrame({})
    data = UMFutures().klines(symbol, interval, **{"limit": 2})
    kline = oder_klines_concat(kline, date=data[0][0], open=data[0][1], close=data[0][4], high=data[0][2],
                               low=data[0][3], volume=data[0][5], value=data[0][7])
    # logging.info("上个" + interval + "周期：", kline)
    return kline


def klines_concat(klines, date, open, close, high, low, volume, value):
    date_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(date / 1000))
    new_dataframe = {'date': date_str,
                     'open': float(open),
                     'close': float(close),
                     'high': float(high),
                     'low': float(low),
                     'volume': float(volume),
                     'value': float(value),
                     'DIF': float(0),
                     'DEA': float(0),
                     'MACD': float(0),
                     "MA3": float(0),
                     "MA30": float(0),
                     "MA210": float(0),
                     "DIF_state": float(0),
                     'state': int(0), }
    new_dataframe = pd.DataFrame(new_dataframe, index=[0])
    klines = pd.concat([klines, new_dataframe], ignore_index=True)
    if len(klines) > 50:
        DIF, DEA, MACD = ta.MACD(klines['close'].values, fastperiod=12, slowperiod=26, signalperiod=9)
        klines['MACD'].values[-1] = float(MACD[-1])
        klines['DIF'].values[-1] = float(DIF[-1])
        klines['DEA'].values[-1] = float(DEA[-1])
        klines['MA3'].values[-1] = float(BinanceKlinesTool.MA(klines, 3))
        klines['MA30'].values[-1] = float(BinanceKlinesTool.MA(klines, 30))
        klines['MA210'].values[-1] = float(BinanceKlinesTool.MA(klines, 210))
        klines = set_DIF_state(klines)

    if len(klines) > 1000:
        klines = klines[-1000:]

    return klines


def oder_klines_concat(klines, date=0, open=0, close=0, high=0, low=0, volume=0, value=0):
    klines = klines_concat(klines, date=date, open=open, close=close, high=high,
                           low=low, volume=volume, value=value)
    klines = set_state(klines)
    return klines


def now_klines_concat(klines, date=0, open=0, close=0, high=0, low=0, volume=0, value=0, interval='1m'):
    last_date = str(klines['date'].values[-2])
    last_date = time.strptime(last_date, "%Y-%m-%d %H:%M:%S")
    last_date = time.mktime(last_date) * 1000
    if (date - last_date) < BinanceKlinesTool.interval_to_second(interval) * 1000 * 2:  # 对最后一条进行更新

        date_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(date / 1000))
        klines['date'].values[-1] = date_str
        klines['open'].values[-1] = float(open)
        klines['close'].values[-1] = float(close)
        klines['high'].values[-1] = float(high)
        klines['low'].values[-1] = float(low)
        klines['volume'].values[-1] = float(volume)
        klines['value'].values[-1] = float(value)

        DIF, DEA, MACD = ta.MACD(klines['close'].values, fastperiod=12, slowperiod=26, signalperiod=9)
        klines['MACD'].values[-1] = float(MACD[-1])
        klines['DIF'].values[-1] = float(DIF[-1])
        klines['DEA'].values[-1] = float(DEA[-1])
        klines['MA3'].values[-1] = float(BinanceKlinesTool.MA(klines, 3))
        klines['MA30'].values[-1] = float(BinanceKlinesTool.MA(klines, 30))
        klines['MA210'].values[-1] = float(BinanceKlinesTool.MA(klines, 210))

        klines = set_DIF_state(klines)

        # 预测当前转折
        now_klines_group = klines_group(klines, 0)
        last_last_klines_group = klines_group(klines, 2)
        last_state = now_klines_group['state'].values[0]

        state = 0  # 0无变化 2转增 -2转减
        if last_state == -1 and klines['close'].values[-1] < last_last_klines_group['close'].min():
            state = 2
        elif last_state == 1 and klines['close'].values[-1] > last_last_klines_group['close'].max():
            state = -2
        klines['state'].values[-1] = state

        return klines

    last_cycle = datetime.datetime.strptime(str(klines['date'].values[-2]), "%Y-%m-%d %H:%M:00")
    second = datetime.timedelta(seconds=BinanceKlinesTool.interval_to_second(interval))  # 周期间隔 s
    klines['date'].values[-1] = last_cycle + second
    klines['state'].values[-1] = 0
    klines = set_state(klines)

    klines = klines_concat(klines, date=date, open=open, close=close, high=high, low=low, volume=volume, value=value)

    return klines


def DIF_state_filter(klines):
    now_DEA = klines['DEA'].values[-1]
    if len(klines.loc[klines['DIF_state'] != 0]) <= 0:
        return True
    if now_DEA < 0:
        last_state_index = klines.loc[klines['DIF_state'] != 0].index[-1]
        for DIF in klines[last_state_index - 1:]['DIF'].values:
            if DIF > 0:
                return True
        return False
    elif now_DEA > 0:
        last_state_index = klines.loc[klines['DIF_state'] != 0].index[-1]
        for DIF in klines[last_state_index - 1:]['DIF'].values:
            if DIF < 0:
                return True
        return False


def set_DIF_state(klines):
    if DIF_state_filter(klines):
        if 0 > klines['DEA'].values[-1] > klines['DIF'].values[-2] and \
                klines['DIF'].values[-1] > klines['DEA'].values[-2]:
            klines['DIF_state'].values[-1] = 1
        elif 0 < klines['DEA'].values[-1] < klines['DIF'].values[-2] and \
                klines['DIF'].values[-1] < klines['DEA'].values[-2]:
            klines['DIF_state'].values[-1] = -1
        else:
            klines['DIF_state'].values[-1] = 0
    return klines


def set_state(klines):
    if len(klines) < 3:
        return klines

    if klines['MACD'].values[-3] < klines['MACD'].values[-2] and klines['MACD'].values[-1] < klines['MACD'].values[-2]:
        klines['state'].values[-2] = -1
    elif klines['MACD'].values[-3] > klines['MACD'].values[-2] and klines['MACD'].values[-1] > klines['MACD'].values[
        -2]:
        klines['state'].values[-2] = 1
    else:
        klines['state'].values[-2] = 0
    return klines


def klines_group(klines, sort):
    if klines['state'].values[-1] != 0:
        sort += 1
    index_list = klines.loc[klines['state'] != 0].index

    end_index = index_list[-sort]
    start_index = index_list[-(sort + 1)]
    if sort == 0:
        return klines[start_index - 1:]
    else:
        return klines[start_index - 1:end_index]


def DIF_range(klines, sort: int):
    index_list = klines.loc[klines['DIF_state'] != 0].index
    start_index = index_list[sort]
    if sort == -1:
        return klines[start_index - 1:]
    else:
        end_index = index_list[sort + 1]
        return klines[start_index - 1:end_index]


def DIF_top_range(klines, sort: int):

    var = DIF_range(klines, sort)
    if var['DIF_state'].values[0] == -1:
        var = DIF_range(klines, sort - 1)
    return var


def DIF_bottom_range(klines, sort: int):
    var = DIF_range(klines, sort)
    if var['DIF_state'].values[0] == 1:
        var = DIF_range(klines, sort - 1)
    return var


def twist_klines(klines):
    var = klines[0:len(klines) - 1].loc[klines['state'] != 0]
    return var
